package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

func main() {
	//回调函数
	NewPromise(func(res Reslove, rej Reject) {
		time.Sleep(time.Second * 2)
		if time.Now().Unix()%2 == 0 {
			res("等于 0")
		} else {
			rej(fmt.Errorf("不等于0"))
		}
	}).Then(func(i interface{}) {
		fmt.Printf("i= %v\n", i)
	}).Cach(func(e error) {
		fmt.Printf("e= %v\n", e)
	}).Done(WithTimeOut(time.Second * time.Duration(1)))
}

type Reslove func(interface{})
type Reject func(error)
type PerformsFunc func(res Reslove, rej Reject)
type Promise struct {
	f       PerformsFunc
	res     Reslove
	rej     Reject
	wg      sync.WaitGroup
	timeout time.Duration
}
type PromiseOpt func(promise *Promise)
type PromiseOpts []PromiseOpt

func (this *PromiseOpts) apply(p *Promise) {
	for _, v := range *this {
		v(p)
	}
}

//超时控制
func WithTimeOut(t time.Duration) PromiseOpt {
	return func(promise *Promise) {
		promise.timeout = t
	}
}

func NewPromise(f PerformsFunc) *Promise {
	return &Promise{
		f:  f,
		wg: sync.WaitGroup{},
	}
}

func (this *Promise) Then(res Reslove) *Promise {
	this.res = res
	return this
}

func (this *Promise) Cach(rej Reject) *Promise {
	this.rej = rej
	return this
}

func (this *Promise) Done(opt ...PromiseOpt) {
	defer func() {
		if e := recover(); e != nil {
			this.rej(fmt.Errorf(e.(string)))
		}
	}()
	ops := PromiseOpts(opt)
	ops.apply(this)
	timeoutContex, _ := context.WithTimeout(context.Background(), this.timeout)

	done := make(chan struct{})
	this.wg.Add(1)
	go func() {
		defer this.wg.Done()
		this.f(this.res, this.rej)
	}()

	go func() {
		defer func() {
			done <- struct{}{}
		}()
		this.wg.Wait()
	}()

	select {
	case <-timeoutContex.Done():
		panic("time out")
	case <-done:
		fmt.Println("正常执行")
	}

}
